#!/usr/bin/env python

import re
try:
	from collections import OrderedDict
except ImportError:
	from ordereddict import OrderedDict

class bitem(object):
	def __init__(self, data):
		"""data must be a string, int, dict or list"""
		self.__len = 0
		if isinstance(data, basestring):
			self.dataType = str
		elif isinstance(data, int):
			self.dataType = int
		elif isinstance(data, dict):
			self.dataType = dict
		elif hasattr(data, "__iter__"):
			self.dataType = list
		else:
			raise TypeError("unsupported data type `%s'" % type(data))
		self.data = data

	def __str__(self):
		if self.dataType == str:
			return "%d:%s" % (len(self.data), self.data)
		elif self.dataType == int:
			return "i%de" % self.data
		elif self.dataType == list:
			return "l%se" % "".join( (str(bitem(x)) for x in self.data) )
		elif self.dataType == dict:
			return "d%se" % "".join( ( "%s%s" % (bitem(k), bitem(v)) for k, v in self.data.iteritems() ) )

def bencode(*data):
	"""Return a bencoded string of the given arguments"""
	ret = ""
	for item in data:
		ret += "%s" % bitem(item)
	return ret

def bdecode(data, inlist = False):
	"""Decode a given bencoded string. Returns a list of string, int, dict or list objects"""
	ret = []
	while len(data):
		if data[0] == "i":	# string
			new = data[1:].split("e", 1)
			ret.append(int(new[0]))
			data = new[1]
		elif data[0] >= "0" and data[0] <= "9":	# int
			r = re.match("^([0-9]+):", data)
			if r:
				l = int(r.group(1)) + r.end()
				ret.append(data[r.end():l])
				data = data[l:]
			else:
				raise ValueError("non-terminated string")
		elif data[0] == "l":	#list
			b = bdecode(data[1:], True)
			ret.append(b[0])
			data = b[1]
		elif data[0] == "d":	#dict
			b = bdecode(data[1:], True)
			l = b[0]
			ret.append(OrderedDict(zip(l[::2], l[1::2])))
			data = b[1]
		elif inlist and data[0] == "e":
			return (ret, data[1:])
		else:
			if len(data) > 20:
				data = data[:20] + "..."
			raise ValueError("malformed bencoded string `%s'" % data)
	return ret
